import React from 'react';

import {
    StyleSheet,
    Text,
    View,
    Animated,
    PanResponder
    } from 'react-native';

let Modal = React.createClass({

    _springFooterHeight: 0,
    _springDamping: 0,

    _defaultShowDuration: 300,
    _defaultHideDuration: 200,

    getInitialState: function() {

        return {
            bottom: new Animated.Value(this.props.isVisible
                ? this._springFooterHeight : -(this.props.height + Math.abs(this._springFooterHeight))),
            isDragging: false,
            isShown: this.props.isVisible
        }
    },

    getDefaultProps: function() {
        return {
            isVisible: false,
            height: 300,
            swipeHideLength: 0.3,
            animatedShowType: 'spring',
            animatedShowConfig: null,
            animatedHideType: 'timing',
            animatedHideConfig: null,
            onWillShow: ()=> {},
            onDidShow: ()=> {},
            onWillHide: ()=> {},
            onDidHide: ()=> {},
        }
    },

    _panResponder: {},

    componentWillMount: function() {
        this._panResponder = PanResponder.create({
            onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
            onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
            onPanResponderGrant: this._handlePanResponderGrant,
            onPanResponderMove: this._handlePanResponderMove,
            onPanResponderRelease: this._handlePanResponderEnd,
            onPanResponderTerminate: this._handlePanResponderEnd,
        });
    },

    shouldComponentUpdate: function(nextProps, nextState) {
        return true
    },

    componentWillReceiveProps: function(nextProps) {

        if(!this.state.isShown && nextProps.isVisible) {
            this.setState({
                isShown: nextProps.isVisible
            })
        }

        if(this.state.isShown && !nextProps.isVisible) {
            this.setState({
                isShown: nextProps.isVisible
            })
        }
    },

    _handleStartShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
        return true;
    },

    _handleMoveShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
        return true;
    },

    _pan: {
        start: {},
        prev: {},
        end: {}
    },

    _handlePanResponderGrant: function(e: Object, gestureState: Object) {
        this._pan.start = e.nativeEvent
        this._pan.prev = e.nativeEvent

        this.setState({
            isDragging: true,
        })
    },

    _handlePanResponderMove: function(e: Object, gestureState: Object) {

        let nextBottom =
            Math.floor(this.state.bottom._value - (e.nativeEvent.pageY - this._pan.prev.pageY))

        if(nextBottom <= this._springFooterHeight) {

            Animated.timing(this.state.bottom, {
                toValue: nextBottom,
                duration: 0
            }).start()

            if(!this.state.isDragging) {
                this.setState({
                    isDragging: true,
                })
            }
        }
        this._pan.prev = e.nativeEvent
    },

    _handlePanResponderEnd: function(e: Object, gestureState: Object) {

        this._pan.end = e.nativeEvent
        this._pan.prev = {}

        if((this._pan.end.pageY - this._pan.start.pageY) >
            ((this.props.height) * this.props.swipeHideLength)) {
            this.setState({
                isDragging: false,
                isShown: false,
            })
        } else {
            this.setState({
                isDragging: false,
            })
        }
    },


    _getModalHeight: function() {
        return this.props.height + Math.abs(this._springFooterHeight)
    },

    _animateShow: function() {
        var config = this.props.animatedShowConfig || {
                duration: this._defaultShowDuration
            }

        config.toValue = this._springFooterHeight

        this.props.onWillShow()
        Animated[this.props.animatedShowType](this.state.bottom, config)
            .start(()=> this.props.onDidShow())
    },

    _animateHide: function() {
        var config = this.props.animatedHideConfig || {
                duration: this._defaultHideDuration
            }

        config.toValue = -(this._getModalHeight())

        this.props.onWillHide()
        Animated[this.props.animatedHideType](this.state.bottom, config)
            .start(()=> this.props.onDidHide())
    },

    _getModalStyle: function() {
        let modelStyle = {
            position: 'absolute',
            left: 0,
            right: 0,
            height: this._getModalHeight(),
            bottom: this.state.bottom
        }

        return modelStyle
    },

    componentDidUpdate: function() {
        if(!this.state.isDragging) {
            if(this.state.isShown) {
                this._animateShow()
            } else {
                this._animateHide()
            }
        }
    },

    render: function() {
        //console.log('render')

        return (
            <Animated.View
                style={[this._getModalStyle(), this.props.style]}
                {...this._panResponder.panHandlers}>

                {this.props.children}

            </Animated.View>
        )
    }

})

export default Modal